#include <string>
#include <iostream>
#include <wxx/com/com_ptr.hpp>

namespace com_ptr_test
{
	struct __declspec(uuid("00000000-0000-0000-D023-000000000046")) DummyObject : IUnknown
	{
		DummyObject()
			: refcount(1)
		{
			++outstanding;
			log_call(L"DummyObject()");
		}

		~DummyObject()
		{
			--outstanding;
			log_call(L"~DummyObject()");
		}

		virtual unsigned long __stdcall AddRef() 
		{
			++refcount;
			log_call(L"AddRef()");
			return refcount;
		}

		virtual unsigned long __stdcall Release()
		{
			--refcount;
			log_call(L"Release()");

			if (refcount == 0)
			{
				delete this;
				return 0;
			}

			return refcount;
		}

		virtual HRESULT __stdcall QueryInterface(const IID&, void** ppvObject)
		{
			ppvObject = 0;
			return E_NOINTERFACE;
		}


		void set_name(const std::wstring& n)
		{
			name = n;
		}

	private:
		std::wstring         name;
		unsigned long        refcount;
		static unsigned long outstanding;

		DummyObject& operator=(const DummyObject&);
		DummyObject(const DummyObject&);

		void log_call(const wchar_t * method) const
		{
			using namespace std;
			std::wostream& out = std::wcout;

			out << name << L": " << L"DummyObject::" << method << std::endl;
			out << name << L": refcount    : "       << refcount << std::endl;
			out << name << L": outstanding : "       << outstanding << std::endl;
		} 
	};

	struct DummyObject_factory
	{
		static DummyObject* CreateInstance(const ::CLSID&, wxx::com::clsctx)
		{
			return new DummyObject();
		}
	};

	void run()
	{
		using namespace wxx::com;

		static const ::CLSID CLSID_DoesntMatter = { 0, 1, 2, 3 };
		typedef com_ptr<DummyObject, &__uuidof(DummyObject), DummyObject_factory> ptr_t;
		
		ptr_t b;
		ptr_t a(CLSID_DoesntMatter);
		
		a->set_name(L"a");
		
		{ 
			ptr_t tmp(a); 
			tmp->set_name(L"a(tmp)");

			tmp = new DummyObject();
			tmp->set_name(L"tmp");
		}

		b.create(CLSID_DoesntMatter);
		b->set_name(L"b");

		DummyObject* obj = b.detach();
		obj->Release();
	}
}

unsigned long com_ptr_test::DummyObject::outstanding = 0;